import { ElMessage, ElMessageBox } from 'element-plus';
import { UiButton } from 'ui-widgets';

// args: { refs, config, state, apis, slotsProps, componentTracker }
export default function useCrudActions(args) {
  const expose = {
    ...args,
  };

  expose.updateList = updateList.bind(expose);
  expose.onSelectionChange = onSelectionChange.bind(expose);
  expose.toggleExpandAll = toggleExpandAll.bind(expose);
  expose.onExpand = onExpand.bind(expose);
  expose.onPagination = onPagination.bind(expose);
  expose.onSearch = onSearch.bind(expose);
  expose.onResetSearch = onResetSearch.bind(expose);
  expose.clearSearchModel = clearSearchModel.bind(expose);
  expose.onAdd = onAdd.bind(expose);
  expose.onEdit = onEdit.bind(expose);
  expose.onStatusTrigger = onStatusTrigger.bind(expose);
  expose.onCancel = onCancel.bind(expose);
  expose.onSave = onSave.bind(expose);
  expose.onRemove = onRemove.bind(expose);
  expose.onRemoveByRow = onRemoveByRow.bind(expose);
  expose.getModelKeys = getModelKeys.bind(expose);
  expose.onClosed = onClosed.bind(expose);
  expose.clearUpdateForm = clearUpdateForm.bind(expose);
  expose.setProps = setProps.bind(expose);
  expose.getPresetButton = getPresetButton.bind(expose);

  initPresetOptions(expose);

  return expose;
}

// 加载数据
function updateList() {
  if (!this.apis.list) {
    ElMessage.error('列表接口不存在');
    return;
  }

  this.state.loading = true;

  let params = {};
  if (this.componentTracker.isComponentUsed('SearchForm'))
    params = Object.assign(params, this.slotsProps.searchForm.model);
  if (this.componentTracker.isComponentUsed('Pagination'))
    params = Object.assign(params, {
      [this.config.keyConfig.page]: this.slotsProps.pagination.page,
      [this.config.keyConfig.limit]: this.slotsProps.pagination.limit,
    });

  this.config.events.beforeUpdateList(params);

  return this.apis
    .list(params)
    .then((res) => {
      this.config.events.updateListResolve(res);

      const { listPath, listPathNoPaging, totalPath } = this.config.defaultOptions;

      if (this.componentTracker.isComponentUsed('Pagination')) {
        this.setProps('table', 'data', getPropertyByPath(res, listPath) || []);
        this.setProps('pagination', 'total', getPropertyByPath(res, totalPath));
      } else {
        this.setProps('table', 'data', getPropertyByPath(res, listPathNoPaging) || []);
      }

      // 树形table，刷新列表展开全部
      if (
        this.componentTracker.isComponentUsed('Table') &&
        ('row-key' in this.slotsProps.table || 'rowKey' in this.slotsProps.table)
      ) {
        nextTick(() => {
          this.state.isExpandAll = true;
          this.toggleExpandAll(this.slotsProps.table.data, this.state.isExpandAll);
        });
      }

      // this.emit('update-list-success');
      return res;
    })
    .catch(() => {
      this.setProps('table', 'data', []);
      if (this.componentTracker.isComponentUsed('Pagination')) this.setProps('pagination', 'total', 0);
    })
    .finally(() => {
      this.state.loading = false;
    });
}

function onSelectionChange(value) {
  this.state.selectionValue = value;
  this.state.single = value.length == 1;
  this.state.multiple = value.length > 0;
}

// 刷新列表展开全部
function toggleExpandAll(children, status) {
  children.forEach((item) => {
    this.refs.table.toggleRowExpansion(item, status);
    if (item[this.config.keyConfig.children] && item[this.config.keyConfig.children].length > 0)
      this.toggleExpandAll(item[this.config.keyConfig.children], status);
  });
}

// 分页
function onPagination() {
  this.refs.table.scrollTo({ top: 0 });
  this.onSearch();
}

// 搜索
function onSearch() {
  this.updateList();
}

// 重置搜索
function onResetSearch() {
  this.clearSearchModel();

  this.updateList();
}

function clearSearchModel() {
  // 放置在最前面，避免动态表单误导el-from，初始化错误的字段初始值
  this.refs.searchForm?.resetFields();

  const modelKeys = this.getModelKeys('searchForm');

  modelKeys.forEach((key) => {
    if (key in this.state.cloneSearchModel) {
      this.slotsProps.searchForm.model[key] = deepClone(this.state.cloneSearchModel[key]);
    } else {
      delete this.slotsProps.searchForm.model[key];
    }
  });
}

// 新增
function onAdd() {
  this.state.isEdit = false;
  this.setProps('updateDialog', 'modelValue', true);
}

// 编辑
function onEdit(item) {
  this.state.isEdit = true;
  this.setProps('updateDialog', 'modelValue', true);

  if (this.apis.details) {
    const id = item[this.config.keyConfig.id];
    if (!id) return ElMessage.error(`${this.config.keyConfig.id}不存在`);

    this.setProps('updateDialog', 'loading', true);

    this.apis
      .details(id)
      .then((res) => {
        const details = getPropertyByPath(res, this.config.defaultOptions.detailDataPath);

        const modelKeys = this.getModelKeys('updateForm');

        modelKeys.forEach((key) => {
          if (key in details) {
            this.slotsProps.updateForm.model[key] = details[key];
          }
        });

        this.config.events.editLoaded(details);
        return res;
      })
      .finally(() => {
        this.setProps('updateDialog', 'loading', false);
      });
  } else {
    if (!item) return ElMessage.error('数据不存在');

    this.setProps('updateDialog', 'loading', true);

    nextTick(() => {
      const modelKeys = this.getModelKeys('updateForm');
      modelKeys.forEach((key) => {
        if (key in item) this.slotsProps.updateForm.model[key] = item[key];
      });
      this.setProps('updateDialog', 'loading', false);
      this.config.events.editLoaded(item);
    });
  }
}

// 修改状态
function onStatusTrigger(row, options) {
  if (!this.apis.status) return ElMessage.error('修改状态接口不存在');

  this.apis.status({ id: row[this.config.keyConfig.id], status: row[this.config.keyConfig.status] }).then(
    () => {
      ElMessage.success('修改成功');
    },
    () => {
      if (options && options.activeValue && options.inactiveValue) {
        row[this.config.keyConfig.status] =
          row[this.config.keyConfig.status] == options.activeValue ? options.inactiveValue : options.activeValue;
      }
    },
  );
}

// 取消
function onCancel() {
  this.setProps('updateDialog', 'modelValue', false);
}

// 提交
function onSave() {
  return new Promise((resolve, reject) => {
    this.refs.updateForm.validate(async (valid) => {
      if (valid) {
        if (this.config.events.saveBefore) {
          const result = await Promise.resolve(this.config.events.saveBefore());
          if (!result) return;
        }

        if (this.state.isEdit) {
          if (!this.apis.edit) {
            ElMessage.error('修改接口不存在');
            reject();
          }
          this.apis.edit(this.slotsProps.updateForm.model).then(() => {
            this.setProps('updateDialog', 'modelValue', false);
            ElMessage.success('修改成功');
            this.updateList();
            // this.emit('edit-success');
            resolve();
          }, reject);
        } else {
          if (!this.apis.add) {
            ElMessage.error('新增接口不存在');
            reject();
          }
          this.apis.add(this.slotsProps.updateForm.model).then(() => {
            this.setProps('updateDialog', 'modelValue', false);
            ElMessage.success('新增成功');
            this.updateList();
            // this.emit('add-success');
            resolve();
          }, reject);
        }
      } else {
        reject();
      }
    });
  });
}

// 删除
function onRemove(params, content) {
  if (!this.apis.remove) {
    ElMessage.error('删除接口不存在');
    return;
  }

  return ElMessageBox.confirm(content, '系统提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning',
  })
    .then(async () => {
      await this.apis
        .remove(params)
        .then(() => {
          ElMessage.success('删除成功');
          this.updateList();
        })
        .catch(() => {});
    })
    .catch(() => {
      ElMessage.info('已取消删除');
    });
}

function onRemoveByRow(row) {
  return this.onRemove?.(
    row[this.config.keyConfig.id],
    this.config.keyConfig.rowName
      ? `是否确认删除名称为“${getPropertyByPath(row, this.config.keyConfig.rowName)}”的数据项?`
      : '是否确认删除该数据项?',
  );
}

// 关闭弹窗后
function onClosed() {
  this.clearUpdateForm();
}

// 清空表单数据
function clearUpdateForm() {
  // table修改状态时，抽屉未打开，表单还未渲染，这种情况updateFormRef不存在
  // 放置在最前面，避免动态表单误导el-from，初始化错误的字段初始值
  this.refs.updateForm?.resetFields();

  const modelKeys = this.getModelKeys('updateForm');

  modelKeys.forEach((key) => {
    if (key in this.state.cloneUpdateModel) {
      this.slotsProps.updateForm.model[key] = deepClone(this.state.cloneUpdateModel[key]);
    } else delete this.slotsProps.updateForm.model[key];
  });
}

function onExpand() {
  if (
    this.componentTracker.isComponentUsed('Table') &&
    ('row-key' in this.slotsProps.table || 'rowKey' in this.slotsProps.table)
  ) {
    this.state.isExpandAll = !this.state.isExpandAll;

    this.toggleExpandAll(this.slotsProps.table.data, this.state.isExpandAll);
  }
}

function initPresetOptions(actions) {
  // 表格操作
  actions.preset = {
    leftToolbar: [
      {
        prop: 'add',
        fieldType: markRaw(UiButton),
        fieldOptions: {
          label: '新增',
          type: 'primary',
          onClick: actions.onAdd,
        },
      },
      {
        prop: 'edit',
        fieldType: markRaw(UiButton),
        fieldOptions: {
          label: '修改',
          type: 'default',
          disabled: computed(() => !actions.state.single),
          onClick: () => actions.onEdit(actions.state.selectionValue[0]),
        },
      },
      {
        prop: 'remove',
        fieldType: markRaw(UiButton),
        fieldOptions: {
          label: '删除',
          type: 'default',
          disabled: computed(() => !actions.state.multiple),
          onClick: () =>
            actions.onRemove(
              actions.state.selectionIds,
              actions.config.keyConfig.rowName
                ? `是否确认删除名称为“${actions.state.selectionNames}”的数据项？`
                : `是否确认删除该数据项?`,
            ),
        },
      },
      {
        prop: 'expand',
        fieldType: markRaw(UiButton),
        fieldOptions: {
          label: '展开/折叠',
          type: 'default',
          onClick: actions.onExpand,
        },
      },
    ],
    tableControls: [
      {
        prop: 'edit',
        fieldType: markRaw(UiButton),
        fieldOptions: { label: '修改', link: true, type: 'primary', onClick: (scope) => actions.onEdit(scope.row) },
      },
      {
        prop: 'remove',
        fieldType: markRaw(UiButton),
        fieldOptions: {
          label: '删除',
          link: true,
          type: 'danger',
          onClick: (scope) => actions.onRemoveByRow(scope.row),
        },
      },
    ],
    updateDialogFooter: [
      { prop: 'cancel', fieldType: markRaw(UiButton), fieldOptions: { label: '取消', onClick: actions.onCancel } },
      {
        prop: 'submit',
        fieldType: markRaw(UiButton),
        fieldOptions: { label: '确定', type: 'primary', onClick: actions.onSave },
      },
    ],
  };
}

// #region 公共方法
function setProps(slotsPropsKey, key, val) {
  const emitName = `onUpdate:${key}`;
  const slotsProps = typeof slotsPropsKey === 'string' ? this.slotsProps[slotsPropsKey] : slotsPropsKey;

  if (slotsProps[emitName]) {
    if (Array.isArray(slotsProps[emitName])) {
      slotsProps[emitName].forEach((item) => {
        item(val);
      });
    } else {
      slotsProps[emitName](val);
    }
  } else {
    slotsProps[key] = val;
  }
}

function getPropertyByPath(obj, path) {
  if (!path) return obj;

  const parts = path.split('.');
  let current = obj;
  for (const part of parts) {
    if (current === undefined || current === null) {
      break;
    }
    current = current[part];
  }
  return current;
}

function getModelKeys(slotsPropsKey) {
  // 编辑id + 表单model定义的key + 表单options定义的prop + 表单fieldOptions定义的'onUpdate:**'
  const keys = [];
  if (slotsPropsKey === 'updateForm') keys.push(this.config.keyConfig.editId || this.config.keyConfig.id);

  keys.push(...Object.keys(this.slotsProps[slotsPropsKey].model));

  const optionsKeys = this.slotsProps[slotsPropsKey].options.map((item) => {
    return item.prop;
  });

  keys.push(...optionsKeys);

  return [...new Set(keys)];
}

function deepClone(source) {
  if (!source || !Array.isArray(source) || validType(source, 'Object')) return source;

  const targetObj = source.constructor === Array ? [] : {};
  Object.keys(source).forEach((keys) => {
    targetObj[keys] = source[keys] && typeof source[keys] === 'object' ? deepClone(source[keys]) : source[keys];
  });
  return targetObj;
}

// 判断类型
function validType(value, type) {
  return Object.prototype.toString.call(value) === `[object ${type}]`;
}

// 预设配置
function getPresetButton(presetName, options) {
  const presetOptions = this.preset[presetName] || [];
  return options.map((item) => {
    if (typeof item === 'string') {
      const res = presetOptions.find((p) => p.prop === item);
      return res ? { ...res } : { prop: item, fieldType: markRaw(UiButton), fieldOptions: { label: item } };
    } else {
      if (typeof item === 'object') {
        const res = presetOptions.find((p) => p.prop === item.prop);
        if (res) {
          const target = deepClone(res);
          deepMerge(target, item);
          return target;
        }
      }
    }
    return item;
  });
}

// 深度合并
export function deepMerge(target, source) {
  for (const key in source) {
    if (validType(source[key], 'Object')) {
      if (!target[key]) target[key] = {};
      deepMerge(target[key], source[key]);
    } else if (validType(source[key], 'Array')) {
      if (!target[key]) target[key] = [];
      target[key] = target[key].concat(source[key]);
    } else {
      target[key] = source[key];
    }
  }
}
// #endregion